<!-- VideoEditorDemo.vue (已修复版) -->
<template>
	<view class="page-container">
		<!-- 1. 功能切换与工具栏 (无变化) -->
		<view class="toolbar-wrapper">
			<view class="mode-switcher">
				<button size="mini" @click="togglePreview" :disabled="!editorCtx">
					{{ isPreview ? '返回编辑' : '进入预览' }}
				</button>
			</view>
			<view class="format-toolbar" v-show="!isPreview">
				<view :class="['tool-item', { active: formats.bold }]" @click="format('bold')">B</view>
				<view :class="['tool-item', { active: formats.italic }]" @click="format('italic')">I</view>
				<view class="tool-item" @click="insertVideo">🎬</view>
			</view>
		</view>

		<!-- 2. 编辑器实例 (无变化) -->
		<editor
			v-show="!isPreview"
			id="videoEditor"
			class="editor-instance"
			placeholder="点击 🎬 按钮，尝试插入一个视频..."
			@ready="onEditorReady"
			@statuschange="onStatusChange"
			:show-img-size="true"
			:show-img-toolbar="true"
		></editor>

		<!-- 3. 【重大改造】预览区域：从单个rich-text改为节点化渲染 -->
		<view v-if="isPreview" class="preview-area">
			<!-- 循环渲染节点数组 -->
			<view v-for="(node, index) in nodes" :key="index">
				<!-- 如果是文本节点，使用 rich-text 渲染 -->
				<rich-text v-if="node.type === 'text'" :nodes="node.content"></rich-text>
				<!-- 如果是视频节点，使用原生 video 组件渲染 -->
				<view v-else-if="node.type === 'video'" class="video-wrapper">
					<video :src="node.src" controls style="width: 100%"></video>
					<p style="font-size: 12px; color: #999; text-align: center">视频预览</p>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
export default {
	data() {
		return {
			editorCtx: null,
			isPreview: false,
			formats: {},
			// 【改造】不再使用 processedHtml 字符串，而是使用一个节点数组
			nodes: [], // e.g. [ {type: 'text', content: '...'}, {type: 'video', src: '...'} ]
			demoText:
				'<iframe class="ql-video" frameborder="0" allowfullscreen="true" src="https://lf-cdn.trae.com.cn/obj/trae-com-cn/bannerIntro425.mp4"></iframe><h1><br></h1><h1><span style="color: rgb(51, 51, 51);" class="ql-size-large">范德萨范德萨</span></h1><p><br></p><p><span class="ql-size-huge">网上老年大学，是中国老年大学协会战略合作伙伴，全国老年大学官方线上学习APP，为全国中老年朋友提供知识、资讯、娱乐等优质服务，帮助中老年朋友更好地适应数字化生活。</span></p><p><br></p><p><br></p><p><img src="https://jwxtcdn.jinlingkeji.cn/saastest/308/2025-05/96f8e36b996e1f3b497796061006df43.jpg"></p>'
		};
	},
	methods: {
		/**
		 * @description 【V5.0 最终版】通用HTML转Nodes解析器（简化版）
		 * @param {string} html - 包含多种标签的富文本字符串
		 * @returns {Array} - uni-app rich-text 组件所需的 nodes 数组
		 */
		htmlToNodes(html) {
			if (!html) return [];

			const nodes = [];
			// 正则表达式，用于匹配 <iframe>, <img>, <p>, <h1> 和文本内容
			// 这是一个简化的匹配，可能无法处理复杂的嵌套
			const regex = /(<iframe[^>]*>[\s\S]*?<\/iframe>)|(<img[^>]*>)|(<h[1-6][^>]*>[\s\S]*?<\/h[1-6]>)|(<p[^>]*>[\s\S]*?<\/p>)|([\s\S]+?)(?=<[a-z]|\s*$)/gi;

			html.replace(regex, (match, iframe, img, heading, p, text) => {
				if (iframe) {
					// 匹配到 iframe -> 转换为 video 节点
					const srcMatch = iframe.match(/src="([^"]+)"/);
					const classMatch = iframe.match(/class="([^"]+)"/);
					if (srcMatch) {
						nodes.push({
							name: 'video',
							attrs: {
								src: srcMatch[1],
								class: classMatch ? classMatch[1] : 'video-style', // 给个默认class
								controls: true,
								style: 'width: 100%;'
							}
						});
					}
				} else if (img) {
					// 匹配到 img -> 转换为 image 节点
					const srcMatch = img.match(/src="([^"]+)"/);
					if (srcMatch) {
						nodes.push({
							name: 'img',
							attrs: {
								src: srcMatch[1],
								style: 'max-width: 100%;'
							}
						});
					}
				} else if (heading || p) {
					// 匹配到标题或段落，这里做简化处理，只提取文本
					// 一个完整的解析器需要递归处理内部的 <span> 等标签
					const tagContent = heading || p;
					const textOnly = tagContent.replace(/<[^>]+>/g, ''); // 粗暴地去掉所有内部标签
					if (textOnly.trim()) {
						nodes.push({
							name: 'p', // 统一用p标签展示
							children: [
								{
									type: 'text',
									text: textOnly
								}
							]
						});
					}
				} else if (text && text.trim()) {
					// 匹配到纯文本
					nodes.push({
						type: 'text',
						text: text.trim()
					});
				}
			});
			return nodes;
		},
		// 在 getEditorContent 中调用
		previewContent() {
			this.editorCtx.getContents({
				success: (res) => {
					const nodes = this.htmlToNodes(res.html);
					// 将nodes数组交给rich-text组件渲染
					// this.nodes = nodes;
				}
			});
		},
		// onEditorReady, onStatusChange, format, insertVideo 方法无变化
		onEditorReady() {
			uni
				.createSelectorQuery()
				.select('#videoEditor')
				.context((res) => {
					this.editorCtx = res.context;
				})
				.exec();
		},
		onStatusChange(e) {
			this.formats = e.detail;
		},
		format(name, value) {
			this.editorCtx.format(name, value);
		},
		insertVideo() {
			const mockVideoUrl = 'https://lf-cdn.trae.com.cn/obj/trae-com-cn/bannerIntro425.mp4';
			const mockCoverUrl = 'https://img.88tph.com/87/c9/h8m8dbbfEeyEcQAWPgWqLw-1.jpg!/fw/700/watermark/url/L3BhdGgvbG9nby5wbmc/align/center';
			this.editorCtx.insertImage({
				src: mockCoverUrl,
				alt: '视频占位符',
				data: { from: 'video-placeholder', 'video-url': mockVideoUrl },
				success: () => {
					this.editorCtx.insertText({ text: '\n' });
				}
			});
		},

		/**
		 * @description 核心方法2：切换预览模式并处理内容
		 */
		togglePreview() {
			this.isPreview = !this.isPreview;
			if (this.isPreview) {
				this.editorCtx.getContents({
					success: (res) => {
						const rawHtml = res.html;
						console.log('获取到的原始HTML:', rawHtml);
						// 【改造】调用新的解析函数，将HTML转换为节点数组
						this.nodes = this.parseHtmlToNodes(rawHtml);
						console.log('处理后的节点数组:', this.nodes);
					}
				});
			} else {
				// 返回编辑时清空节点，释放内存
				this.nodes = [];
			}
		},

		/**
		 * @description HTML解析器
		 * 使用正确的查询字符串解析器，应对最终的数据格式
		 */
		parseHtmlToNodes(html) {
			const nodes = [];
			// 这个正则表达式本身是正确的，它成功捕获了 data-custom 的内容，所以不需要改
			const regex = /<img(?=[^>]*\ssrc="([^"]+)")[^>]*data-custom="([^"]+)"[^>]*>/gi;

			let lastIndex = 0;
			let match;

			while ((match = regex.exec(html)) !== null) {
				const textBefore = html.substring(lastIndex, match.index);
				if (textBefore) {
					nodes.push({ type: 'text', content: textBefore });
				}

				const posterUrl = match[1];
				const customDataString = match[2]; // 这就是那个 "from=...&amp;video-url=..." 字符串

				try {
					// 不使用 JSON.parse，而是使用我们自己的查询字符串解析器
					const customData = this.parseQueryString(customDataString);
					if (customData.from === 'video-placeholder' && customData['video-url']) {
						nodes.push({
							type: 'video',
							src: customData['video-url'],
							poster: posterUrl
						});
					} else {
						nodes.push({ type: 'text', content: match[0] });
					}
				} catch (e) {
					console.error('解析 custom data 失败:', e, '原始字符串:', customDataString);
					nodes.push({ type: 'text', content: match[0] });
				}

				lastIndex = regex.lastIndex;
			}

			const textAfter = html.substring(lastIndex);
			if (textAfter) {
				nodes.push({ type: 'text', content: textAfter });
			}

			if (nodes.length === 0 && html.length > 0) {
				nodes.push({ type: 'text', content: html });
			}

			return nodes;
		},

		/**
		 * @description 辅助函数：解析URL查询字符串
		 * @param {string} str - 例如 "key1=value1&amp;key2=value2"
		 * @returns {object} - 例如 { key1: 'value1', key2: 'value2' }
		 */
		parseQueryString(str) {
			const result = {};
			// 1. 先将 &amp; 替换回 &
			const decodedStr = str.replace(/&amp;/g, '&');
			// 2. 按 & 分割成键值对数组
			const pairs = decodedStr.split('&');

			for (const pair of pairs) {
				// 3. 按 = 分割键和值
				const [key, value] = pair.split('=');
				if (key) {
					// 4. 使用 decodeURIComponent 来解码值，以防URL中有特殊字符
					result[key] = decodeURIComponent(value || '');
				}
			}
			return result;
		}
	}
};
</script>

<style scoped>
/* 样式基本无变化，可按需添加 .video-wrapper 的样式 */
.page-container {
	display: flex;
	flex-direction: column;
	height: 100vh;
}
.toolbar-wrapper {
	padding: 10px;
	border-bottom: 1px solid #e0e0e0;
	background: #fff;
}
.mode-switcher {
	margin-bottom: 10px;
	text-align: right;
}
.format-toolbar {
	display: flex;
	align-items: center;
	gap: 15px;
}
.tool-item {
	display: flex;
	justify-content: center;
	align-items: center;
	width: 30px;
	height: 30px;
	font-size: 18px;
	font-weight: bold;
	border-radius: 4px;
	transition: background-color 0.2s;
	cursor: pointer;
}
.tool-item:hover {
	background-color: #efefef;
}
.tool-item.active {
	background-color: #e0e0e0;
}
.editor-instance {
	flex: 1;
	width: 100%;
	padding: 15px;
	box-sizing: border-box;
	background: #fff;
}
.preview-area {
	flex: 1;
	padding: 15px;
	background: #f7f7f7;
	overflow-y: auto;
}
.video-wrapper {
	margin: 10px 0;
}
</style>
